//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <winhack.h>
#include <elasys_server.h>
#include <linknode.h>
#include <sysconfig.h>
#include <stdlib.h>

typedef class StringNode StringNode;

class StringNode
{
public:
    StringNode(wchar_t *key, wchar_t *value);
    ~StringNode();
    StringNode * Prev()    { return (StringNode *) m_list.Prev(); }
    StringNode * Next()    { return (StringNode *) m_list.Next(); }
public:
    DoubleLinkNode m_list;
    wchar_t *m_key;
    wchar_t *m_value;
};

StringNode::StringNode(wchar_t *keyWord, wchar_t *value) : m_key(0), m_value(0)
{
    //assert(keyWord || value);
    this->m_list.Initialize();
    int len;
    if (keyWord) {
        len = wcslen(keyWord) + 1;
        m_key = (wchar_t *)malloc(len * sizeof(wchar_t));
        if (!m_key)
            return;
        else
            wcscpy(m_key, keyWord);
    }

    if (value) {
        len = wcslen(value) + 1;
        m_value = (wchar_t *)malloc(len * sizeof(wchar_t));
        if (!m_value)
            return;
        else
            wcscpy(m_value, value);
    }
}

StringNode::~StringNode()
{
    if (m_key)
        free(m_key);
    if (m_value)
        free(m_value);
}

static StringNode *g_pHead;

extern "C" void ConfigInitDic()
{
    g_pHead = (StringNode *) new StringNode(L"", L"");
}

extern "C" void ConfigDestroyDic()
{
    StringNode *pTempNote;
    pTempNote = g_pHead->Next();
    while (g_pHead != pTempNote) {
        pTempNote->m_list.Detach();
        delete pTempNote;
        pTempNote = g_pHead->Next();
    }
    delete g_pHead;
}

StringNode* FindNode(StringNode* pNode)
{
    StringNode *pTempNode = g_pHead->Next();
    if (pTempNode != NULL) {
        do {
            if (0 == wcscmp(pNode->m_key, pTempNode->m_key)) {
                return pTempNode;
            }
            pTempNode=pTempNode->Next();
        } while (pTempNode != g_pHead);
    }

    return NULL;
}

ECode Add(
    /* [in] */ wchar_t *key,
    /* [in] */ wchar_t *value)
{
    if (NULL == key || wcslen(key) == 0 || NULL == value
        || wcslen(value) == 0)
        return E_INVALID_ARGUMENT;

    StringNode *pNode =
        (StringNode *) new StringNode(key, value);
    if (!pNode)
        return E_OUT_OF_MEMORY;
    if (FindNode(pNode) != NULL) {
        delete (StringNode *)pNode;
        return E_INVALID_ARGUMENT;
    }
    g_pHead->m_list.InsertNext((DoubleLinkNode *) &(pNode->m_list));
    return NOERROR;
}

extern "C" ECode ConfigSetItem(
    /* [in] */ wchar_t *key,
    /* [in] */ wchar_t *value)
{
    if (NULL == key || wcslen(key) == 0 || NULL == value
        || wcslen(value) == 0)
        return E_INVALID_ARGUMENT;

    StringNode Node(key, NULL);
    StringNode *pTempNode = NULL;

    pTempNode = FindNode(&Node);
    if (!pTempNode) {
        return Add(key, value);
    }
    Int32 len = wcslen(value);
    if ((size_t)len > wcslen(pTempNode->m_value)) {
        pTempNode->m_value = (wchar_t *)realloc(pTempNode->m_value,
                (len+1) * sizeof(wchar_t));
    }
    ECode ec;
    if (pTempNode->m_value) {
        wcscpy(pTempNode->m_value, value);
        ec = NOERROR;
    }
    else
        ec = E_OUT_OF_MEMORY;

    return ec;
}

extern "C" ECode ConfigGetItemStr(
    /* [in] */ wchar_t *key,
    /* [out] */ wchar_t *value)
{
    if (NULL == key || wcslen(key) == 0
        || NULL == value)
        return E_INVALID_ARGUMENT;

    StringNode Node(key, NULL);
    StringNode *pTempNode = NULL;

    pTempNode = FindNode(&Node);
    if (!pTempNode) {
        return E_ACCESS_DENIED;
    }
    wcscpy(value, pTempNode->m_value);
    if ((int)wcslen(value) < (int)wcslen(pTempNode->m_value))
        return E_BUFFER_TOO_SMALL;
    return NOERROR;
}

extern "C" ECode ConfigGetItemInt(
    /* [in] */ wchar_t *key,
    /* [out] */int *value)
{
    if (NULL == key || wcslen(key) == 0
        || NULL == value)
        return E_INVALID_ARGUMENT;

    StringNode Node(key, NULL);
    StringNode *pTempNode = NULL;

    pTempNode = FindNode(&Node);
    if (!pTempNode) {
        return E_ACCESS_DENIED;
    }
    wchar_t *stops;
    *value = (int)wcstol(pTempNode->m_value, &stops, 10);
    return NOERROR;
}
